//【Day19】LeetCode算法刷题（附带解题思路、代码注释详细） 【777. 在LR字符串中交换相邻字符】 【54. 螺旋矩阵】







/* 【777. 在LR字符串中交换相邻字符】
题目描述：

在一个由'L','R'和'X'三个字符组成的字符串（例如"RXXLRXRXL"）中进行移动操作。一次移动操作指用一个"LX"替换一个"XL"，或者用一个"XR"替换一个"RX"。现给定起始字符串start和结束字符串end，请编写代码，当且仅当存在一系列移动操作使得start可以转换成end时，
返回True。
/
示例 :
输入: start = “RXXLRXRXL”, end = “XRLXXRRLX”
输出: True
解释:
我们可以通过以下几步将start转换成end:
RXXLRXRXL ->
XRXLRXRXL ->
XRLXRXRXL ->
XRLXXRRXL ->
XRLXXRRLX
/
提示：
1 <= len(start) = len(end) <= 10000。
start和end中的字符串仅限于’L’, ‘R’和’X’。

解题思路：
为了确定start字符串是否可以通过交换相邻字符获得end字符串，我们可以同时遍历两个字符串，当遇到可以确定两者不能通过交换字符而相等的情况时，返回false即可，完全遍历完说明符合条件，返回true；

那么我们应该怎么判断情况呢？

通过题目我们可以知道，交换字符是通过：‘RX’ 替换成 ‘XR’ 或 ‘XL’ 替换成 ‘LX’ 实现的，如果两者符合条件可以交换相邻字符获取对方，当将字符串中所有字符‘L’删去，剩下的两个字符串是相同的。

①反过来想，我们便利时忽略掉字符‘L’，当遍历的两个字符不相等时，就能确定不符合条件，返回false了。

到这里还不能完全排除不符合条件的情况，另一个情况如下，那就是：

②根据规则：一个"LX"替换一个"XL"，或者用一个"XR"替换一个"RX"。

当start字符串遍历到L或者R，都因该是XL或RX，而end字符串是LX或XR
所以当start遍历到L，下标i应该 大于等于 end字符串的下标j，因为start中XL的L在X之后
所以当start遍历到R，下标i应该 小于等于 end字符串的下标j，因为start中RX的R在X之前
 如果遇到不符合上述描述的情况，搜可以返回false了
③我们按照上述的操作推演一下，就知道这最后一个元素会是’X’，否则返回false

当两个字符串都顺利遍历完，说明排除了所有无法交换获得的情况，可以返回true。
————————————————
版权声明：本文为CSDN博主「.29.」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/ebb29bbe/article/details/127140777 */




class Solution {
    public boolean canTransform(String start, String end) {
        int n = start.length();    //获取字符串长度，方便遍历
        int i = 0,j = 0;           //用i表示start字符串下标，用j表示end字符串下标

        while(i < n && j < n){     //同时遍历
            while(i < n && start.charAt(i) == 'X'){//跳过start字符串中的‘X’
                ++i;
            }
            while(j < n && end.charAt(j) == 'X'){  //跳过end字符串中的‘X’
                ++j;
            }

            if(i < n && j < n){
                //忽略掉‘X’字符发现剩下的字符不对应，说明无法通过交换相邻字符获得
                if(start.charAt(i) != end.charAt(j)){ 
                    return false;
                }
//当我们按照前面的步骤遍历，根据规则：一个"LX"替换一个"XL"，或者用一个"XR"替换一个"RX"。
//当start字符串遍历到L或者R，都因该是XL或RX，而end字符串是LX或XR
//所以当start遍历到L，下标i应该 大于等于 end字符串的下标j，因为start中XL的`L`在`X`之后
//所以当start遍历到R，下标i应该 小于等于 end字符串的下标j，因为start中RX的`R`在`X`之前
//所以遇到不符合上述描述的情况，搜可以返回false了
                char ch = start.charAt(i);
                if(ch == 'L' && i < j || ch == 'R' && i > j){
                    return false;
                }
                ++i;++j;
            }
        }
        //当我们遍历到最后，一个字符串已经遍历完成，剩下一个字符串遍历到最后一个元素
        //我们按照上述的操作推演一下，就知道这最后一个元素会是'X'，否则返回false
        while(i < n && i < j){
            if(start.charAt(i) != 'X')
            return false;
            ++i;
        }
        while(j < n && j < i){
            if(end.charAt(j) != 'X')
            return false;
            ++j;
        }
        //两个字符串遍历完无异常，就说明start可以通过交换相邻字符获得end，返回true
        return true;
    }
}







/*【54. 螺旋矩阵】
题目描述：

给你一个m 行 n 列的矩阵 matrix ，请按照 顺时针螺旋顺序 ，返回矩阵中的所有元素。
/
示例 1：

输入：matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出：[1,2,3,6,9,8,7,4,5]
/
示例 2：

输入：matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出：[1,2,3,4,8,12,11,10,9,5,6,7]

解题思路：
为了让矩阵能按照顺时针螺旋顺序遍历，我们可以先观察，总结这样遍历的特点，而且很轻易就能发现，螺旋矩阵的遍历总是先向左、向下、再向上，最后又向左的，那么我们就可以从这个规律着手。

为了按照旋转矩阵的规律遍历，我们可以设置一个用于翻转数组，改变遍历方向的数组move[][]内容如下：

{0，1}让矩阵向右遍历 行下标row + 0，列下标col + 1
{1，0}让矩阵向下遍历 行下标row + 1，列下标col + 0
{0，-1}让矩阵向左遍历 行下标row + 0，列下标col + -1
{-1，0}让矩阵向上遍历 行下标row + -1，列下标col + 0
我们一边遍历，一边将扫描过的元素存入集合，同时标记扫描过的位置。

当下一个位置没有越界 或 遍历过，就照常遍历，遇到越界 或 扫描过的位置，就利用数组move，改变遍历方向。

重复操作，知道遍历完成即可。
————————————————
版权声明：本文为CSDN博主「.29.」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/ebb29bbe/article/details/127140777*/




class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> list = new ArrayList<>();       //创建集合，记录顺时针螺旋顺序

        //如果矩阵为空或不含元素，返回空集合
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0) 
        return list;

        //获取矩阵的长度rows与高度cols
        int rows = matrix.length;
        int cols = matrix[0].length;
        //定义一个标记矩阵flag，与matrix大小一致，用于标记相同位置上被遍历过的元素
        boolean[][] flag = new boolean[rows][cols];
        //定义一个用于翻转矩阵的二维数组
        //第一行代表向右遍历
        //第二行代表向下遍历
        //第三行代表向左遍历
        //第四行代表向上遍历
        int[][] move = {{0,1},{1,0},{0,-1},{-1,0}};
        //记录当前行、当前列和遍历方向的下标index
        int row = 0,col = 0,index = 0;

        for(int i = 0;i < rows*cols;++i){
            //开始遍历，标记遍历过的位置
            list.add(matrix[row][col]);
            flag[row][col] = true;

            //记录下一位置的行下标和列下标
            int nextRow = row + move[index][0];
            int nextCol = col + move[index][1];

            //如果下一个位置越界或者被遍历过
            if(nextRow < 0 || nextRow >= rows ||
               nextCol < 0 || nextCol >= cols ||
               flag[nextRow][nextCol]){
                   //翻转矩阵进行螺旋遍历
                   index = (index+1)%4;
               }
            
            //向后一个位置挪动
            row += move[index][0];
            col += move[index][1];
            
        }
        return list; //返回按照顺时针螺旋顺序存放元素的集合
        
    }
}




